home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / tsrdemo2.arc / TSRDEMO2.ASM < prev    next >
Encoding:
Assembly Source File  |  1987-04-09  |  44.4 KB  |  1,494 lines

  1. page    60,132
  2. ;==============================================================================
  3. ; TSRDEMO2.ASM
  4. ; Thomas Brandenborg
  5. ; 87.02.11
  6. ;
  7. ; Sample demonstration of a safe approach for writing TSR programmes.
  8. ;
  9. ;------------------------------------------------------------------------------
  10. ; Copyright 1987 by Thomas Brandenborg. All Rights Reserved
  11. ; Written for uploading to Compuserve Forums by
  12. ;    Thomas Brandenborg
  13. ;    Lundbyesgade 11
  14. ;    DK-8000 Aarhus C
  15. ;    DENMARK
  16. ;
  17. ; This code is intended as a reference to users on Compuserve Forums
  18. ; on how to write Terminate-And-Stay resident programmes for Personal
  19. ; Cumputers running under DOS versions 2.00 and newer.
  20. ;
  21. ; The code is not part of any proprietary product, but is rather a
  22. ; demonstration of such techniques that may be used to write safe TSR
  23. ; programmes.
  24. ;
  25. ; All or part of it may, however, be used in other software products
  26. ; or otherwise distributed assuming the copyright holders Name & Address
  27. ; as listed above are included clearly and visibly in the documentation
  28. ; for such product.
  29. ;
  30. ; The copyright holder offers no warranty with this code whatsoever,
  31. ; including its fitness for any particular purpose. Neither shall he
  32. ; be liable for damages of any kind that may arise from its use.
  33. ;
  34. ;
  35. ; IF YOU THINK THIS CODE IS USEFUL:
  36. ;
  37. ; If you think this code has had some value to you, and in particular
  38. ; if you consider using all or parts of it in your own product, you
  39. ; may want to consider a smaller or larger donation to the author
  40. ; (Name & Address above) who spend his late night hours putting
  41. ; it together.
  42. ;
  43. ; As to the size of a such donation this is entirely up to your own
  44. ; judgement. It is suggested that you simply consider the value this
  45. ; code has had to you, the time you saved not having to write it your
  46. ; self... that should help you determine the right amount.
  47. ;
  48. ; Please notice that such donations are an entirely voluntary contribution.
  49. ; This holds true whatever your purpose is for using this code, and whatever
  50. ; the type of product and distribution you work with. The author has nothing
  51. ; against commercial software distribution and does not have any reason
  52. ; to restrict developers of commercial products in their use of this code.
  53. ;------------------------------------------------------------------------------
  54. ; COMPILING:    masm tsrdemo2;
  55. ; LINKING:    link tsrdemo2;
  56. ;         exe2bin tsrdemo2 tsrdemo2.com
  57. ;------------------------------------------------------------------------------
  58. ; Revisions
  59. ; Brandenborg 87.02.14    Added copyright notice & checked comments
  60. ; Brandenborg 87.02.17    Added full AX value in Set Ext Err call
  61. ; Brandenborg 87.02.25    Went through to optimize things
  62. ; Brandenborg 87.02.28    Added auto INT28 invocation in INT16 handler
  63. ; Brandenborg 87.03.01    Added INT21 filter for recursion onto console stack
  64. ; Brandenborg 87.03.02    Final cleanup of comments etc.
  65. ;==============================================================================
  66.  
  67. ;==============================================================================
  68. ; DEFINE BIOS DATA SEGMENT OFFSETS
  69. ;==============================================================================
  70.  
  71. BiosData    segment at 40h
  72.         org    17h
  73. KbFlag        label    byte        ;current shift status bits
  74.         org    18h
  75. KbFlag1        label    byte        ;current key status of toggle keys
  76. BiosData    ends
  77.  
  78. ;==============================================================================
  79. ; DEFINE OFFSETS WITHIN BIOS EXTRA DATA SEGMENT
  80. ;==============================================================================
  81.  
  82. BiosXX        segment at 50h
  83.         org    0
  84. StatusByte    label    byte        ;PrtSc status
  85. BiosXX        ends
  86.  
  87. ErrPrtSc    equ    -1        ;err during last PrtSc
  88. InPrtSc        equ    1        ;PrtSc in progress
  89.  
  90. ;==============================================================================
  91. ; DEFINE OFFSETS WITHIN OUR PSP
  92. ;==============================================================================
  93.  
  94. Cseg        segment byte public
  95.         org    2
  96. TopSeg        label    word        ;last seg in alloc block
  97.         org    2ch
  98. EnvSeg        label    word        ;seg of our environment copy
  99. Cseg        ends
  100.  
  101. ;==============================================================================
  102. ; DOS COM-FILE ENTRY POINT
  103. ;==============================================================================
  104.  
  105. Cseg        segment public byte
  106.         assume    cs:Cseg, ds:nothing, es:nothing, ss:nothing
  107.         org    100h
  108. ComEntry:    jmp    Init        ;JMP to init at bottom of seg
  109.  
  110. ;==============================================================================
  111. ; IDENTIFICATION CODES FOR THIS TSR (MUST BE UNIQUE FOR EACH CO-EXISTING TSR)
  112. ; HIGH BYTE OF GetId MUST NOT MATCH ANY AH REQUEST CODES FOR INT16H.
  113. ;==============================================================================
  114.  
  115. GetId        equ    'tc'            ;INT16h AX val to get MyId
  116. MyId        equ    'TC'            ;ID of this TSR
  117.  
  118. ;==============================================================================
  119. ; FLAGS AND PTRS FOR RESIDENT HANDLING
  120. ;==============================================================================
  121.  
  122. TsrMode        db    0            ;bits for various modes
  123. InInt08        equ    1 SHL 0            ;timer0 tick handler
  124. InInt09        equ    1 SHL 1            ;keyboard handler
  125. InInt13        equ    1 SHL 2            ;BIOS disk I/O
  126. InInt28        equ    1 SHL 3            ;INT28 handler
  127. In28Call    equ    1 SHL 4            ;we have issued INT28
  128. InPopup        equ    1 SHL 5            ;popup routine activated
  129. NewDos        equ    1 SHL 6            ;DOS 2.x in use
  130. InDosClr    equ    1 SHL 7            ;InDos=0 at popup time
  131.  
  132. KeyMode        db    0            ;bits for hotkey status
  133. HotIsShift    equ    1 SHL 0            ;hotkey is shift state
  134. InHotMatch    equ    1 SHL 1            ;so far keys match hotkey seq
  135. HotKeyOn    equ    1 SHL 2            ;full hotkey pressed
  136.  
  137. InDosPtr    label    dword            ;seg:off of InDos flag
  138. InDosOff    dw    0
  139. InDosSeg    dw    0
  140.  
  141. CritErrPtr    label    dword            ;seg:off of CritErr flag
  142. CritErrOff    dw    0
  143. CritErrSeg    dw    0
  144.  
  145. ;==============================================================================
  146. ; DATA FOR INT09H HANDLER TO CHECK FOR HOTKEY COMBINATION
  147. ;==============================================================================
  148.  
  149. ; ------------    EQU'S FOR BIT SHIFTS WITHIN KEYBOARD FLAGS
  150.  
  151. InsState    equ    80h
  152. CapsState    equ    40h
  153. NumState    equ    20h
  154. ScrollState    equ    10h
  155. AltShift    equ    08h
  156. CtlShift    equ    04h
  157. LeftShift    equ    02h
  158. RightShift    equ    01h
  159.  
  160. InsShift    equ    80h
  161. CapsShift    equ    40h
  162. NumShift    equ    20h
  163. ScrollShift    equ    10h
  164. HoldState    equ    08h
  165.  
  166. ; ------------    SCAN CODES FOR VARIOUS SHIFT KEYS
  167.  
  168. LeftDown    equ    42            ;scan code of left shift key
  169. LeftUp        equ    LeftDown OR 80h
  170. RightDown    equ    54            ;scan code of right shift key
  171. RightUp        equ    RightDown OR 80h
  172. AltDown        equ    56            ;scan code of alt key
  173. AltUp        equ    AltDown OR 80h
  174. CtlDown        equ    29            ;scan code of ctrl key
  175. CtlUp        equ    CtlDown OR 80h
  176.  
  177. ; ------------    MISC KEYBOARD DATA
  178.  
  179. KbData        equ    60h            ;keyboard data input
  180.  
  181. ;==============================================================================
  182. ; TO USE A SHIFT KEY COMBINATION AS HOT KEY:
  183. ;  -    SET THE FLAG HotIsShift IN KeyMode
  184. ;  -    DEFINE THE SHIFT STATUS BITS IN THE VARIABLE HotKeyShift
  185. ;
  186. ; TO USE A SERIES OF SCAN CODES AS HOT KEY:
  187. ;    CLEAR THE FLAG HotIsShift IN KeyMode
  188. ;  -    INSERT THE MAKE AND BREAK SCAN CODES IN THE HotKeySeq STRING
  189. ;    NOTE:    WITH THIS DEMO IMPLEMENTATION YOU SHOULD NOT USE A HOT KEY
  190. ;        SEQUENCE WHICH PRODUCES A KEY IN THE BIOS KEYBOARD QUEUE,
  191. ;        SINCE THE KEY IS NOT REMOVED BEFORE CALLING THE POPUP ROUTINE.
  192. ;
  193. ; NOTE:    HOTKEY TYPE AND CONTENTS OF HOTKEY VARIABLES MAY BE CHANGED AT RUN TIME
  194. ;==============================================================================
  195.  
  196. HotKeyShift    db    LeftShift OR RightShift    ;shift state IF HotIsShift=FF
  197.  
  198. HotKeySeq    db    LeftDown,LeftUp,LeftDown,LeftUp
  199. HotKeyLen    equ    $-HotKeySeq
  200. HotIndex    db    0            ;# key in seq to compare next
  201. BetweenKeys    db    0            ;timeout count between keys
  202. KeyTimeOut    equ    10            ;more ticks means not a hotkey
  203.  
  204. ;==============================================================================
  205. ; DATA FOR INT08H HANDLER TO CHECK FOR POPUP
  206. ;==============================================================================
  207.  
  208. SafeWait    db    0            ;count-down for safe popup
  209. MaxWait        equ    8            ;wait no more 8/18 sec
  210.  
  211. ;==============================================================================
  212. ; PROCESS & SYSTEM DATA
  213. ;==============================================================================
  214.  
  215. OurSS        dw    0            ;stack for popup routine
  216. OurSP        dw    0
  217. StackSize    equ    512            ;bytes to reserve for stack
  218.  
  219. OldSS        dw    0            ;old stack seg
  220. OldSP        dw    0            ;old stack off
  221.  
  222. OurPSP        dw    0            ;our PSP seg
  223. OldPSP        dw    0            ;old PSP seg
  224.  
  225. OldDTA        label    dword            ;seg:off of old DTA area
  226. OldDTAOff    dw    0
  227. OldDTASeg    dw    0
  228.  
  229. OurDTA        label    dword            ;seg:off of our DTA
  230. OurDTAOff    dw    0
  231. OurDTASeg    dw    0
  232.  
  233. OldBreak    db    0            ;old ctrl-break state
  234. OldExtErr    dw    3 dup (0)        ;AX,BX,CX of ext err
  235.  
  236. ;==============================================================================
  237. ; LOCATIONS FOR SAVED INTERRUPT VECTORS
  238. ;==============================================================================
  239.  
  240. OldInt08    label    dword            ;Timer0 loaded before this
  241. OldInt08Off    dw    0
  242. OldInt08Seg    dw    0
  243.  
  244. OldInt09    label    dword            ;Kb handler loadde before this
  245. OldInt09Off    dw    0
  246. OldInt09Seg    dw    0
  247.  
  248. OldInt13    label    dword            ;BIOS diskette I/O
  249. OldInt13Off    dw    0
  250. OldInt13Seg    dw    0
  251.  
  252. OldInt16    label    dword            ;BIOS kb Q-handler
  253. OldInt16Off    dw    0
  254. OldInt16Seg    dw    0
  255.  
  256. OldInt1B    label    dword            ;^break of process we steal
  257. OldInt1BOff    dw    0
  258. OldInt1BSeg    dw    0
  259.  
  260. OldInt1C    label    dword            ;timer tick of process we steal
  261. OldInt1COff    dw    0
  262. OldInt1CSeg    dw    0
  263.  
  264. OldInt21    label    dword            ;DOS function dispatcher
  265. OldInt21Off    dw    0
  266. OldInt21Seg    dw    0
  267.  
  268. OldInt23    label    dword            ;^C of process we steal
  269. OldInt23Off    dw    0
  270. OldInt23Seg    dw    0
  271.  
  272. OldInt24    label    dword            ;crit err of process we steal
  273. OldInt24Off    dw    0
  274. OldInt24Seg    dw    0
  275.  
  276. OldInt28    label    dword            ;DOS idles loaded before this
  277. OldInt28Off    dw    0
  278. OldInt28Seg    dw    0
  279.  
  280. ;==============================================================================
  281. ; SPEAKER/TONE GENERATION DATA
  282. ;==============================================================================
  283.  
  284. PB0port        equ    61h            ;port for speaker bit
  285. ErrLen1        equ    10            ;# outer err beep cycles
  286. ErrLen2        equ    80            ;# inner err beep cycles
  287. ErrLow        equ    100            ;low tone wait in err beep
  288. ErrHi        equ    40            ;hi tone wait in err beep
  289.  
  290. ;==============================================================================
  291. ; ErrBeep - PRODUCE ERROR-INDICATING SOUND ON SPEAKER
  292. ;==============================================================================
  293.  
  294. ErrBeep        proc    near
  295.         assume    ds:nothing, es:nothing, ss:nothing
  296.  
  297.         push    ax            ;save regs used
  298.         push    bx
  299.         push    cx
  300.         push    dx
  301.  
  302.         mov    cx,ErrLen1        ;# mix-cycles for beep
  303.  
  304. ErrBeep1:    mov    dx,ErrLow        ;wait time for half-cycle
  305.         mov    bx,ErrLen2        ;len of one tone
  306.         call    DoTone            ;output low err tone
  307.         mov    dx,ErrHi        ;wait time for half-cycle
  308.         mov    bx,ErrLen2        ;len of one tone
  309.         call    DoTone            ;output low err tone
  310.  
  311.         loop    ErrBeep1        ;loop for some time
  312.  
  313.         pop    dx
  314.         pop    cx            ;restore regs
  315.         pop    bx
  316.         pop    ax
  317.         ret
  318. ErrBeep        endp
  319.  
  320. ;==============================================================================
  321. ; DoTone - OUTPUT ONE TONE ON THE SPEAKER
  322. ;
  323. ; INPUT:    DX:    LOOP WAIT TIME FOR HALF CYCLE IN TONE
  324. ;        BX:    NUMBER OF CYCLES FOR TONE DURATION
  325. ; OUTPUT:    NONE
  326. ; REGS:        ALL PRESERVED
  327. ;==============================================================================
  328.  
  329. DoTone        proc    near
  330.         assume    ds:nothing, es:nothing, ss:nothing
  331.  
  332.         push    ax            ;save regs used
  333.         push    bx
  334.         push    cx
  335.         in    al,PB0port        ;get PB0 reg pattern
  336.         mov    ah,al            ;save it
  337.  
  338. DoTone1:    and    al,0fch            ;mask off speaker bit
  339.         out    PB0port,al        ;pull!
  340.         mov    cx,dx            ;half cycle in counter
  341. DoTone2:    loop    DoTone2            ;leave there for half a cycle
  342.         or    al,2            ;turn on speaker bit
  343.         out    PB0port,al        ;push!
  344.         mov    cx,dx            ;half cycle in counter
  345. DoTone3:    loop    DoTone3            ;leave there for half a cycle
  346.  
  347.         dec    bx            ;count down tone duration
  348.         jnz    DoTone1            ;go through full tone
  349.  
  350.         mov    al,ah            ;AL=original PB0 reg value
  351.         out    PB0port,al        ;restore
  352.  
  353.         pop    cx            ;restore regs
  354.         pop    bx
  355.         pop    ax
  356.         ret
  357. DoTone        endp
  358.  
  359. ;==============================================================================
  360. ; TestSafe - CHECK IF THIS IS A SAFE TIME TO DO A POP UP
  361. ; RETURN CLC IF SAFE TO POP UP, CY IF NOT SAFE.
  362. ;
  363. ; CHECK IF ANY INTs ARE IN CRITICAL AREAS (InInt09 & InInt13)
  364. ; CHECK IF WE ARE IN AN OUR OWN INT28 CALL (In28Call)
  365. ; CHECK 8259A PIC ISR REGISTER FOR MISSING EOIs
  366. ; CHECK IF DOS IS STABLE FOR POP UP
  367. ; CHECK IF A PRINT SCREEN IS IN PROGRESS
  368. ;==============================================================================
  369.  
  370. TestSafe    proc    near
  371.         assume    ds:nothing, es:nothing
  372.  
  373.         push    ax            ;save regs used
  374.         push    bx
  375.         push    ds
  376.  
  377. ; ------------    CHECK INTs TO SEE IF THEY WERE INTERRUPTED AT BAD TIMES
  378.  
  379.         test    TsrMode,InInt09 OR InInt13 OR In28Call
  380.         jnz    NotSafe            ;jump if any INTs are chopped
  381.  
  382. ; ------------    CHECK THE 8259A PIC ISR REGISTER FOR NON-EOIed HW INTs
  383.  
  384.         mov    al,00001011b        ;tell 8259A we want the ISR
  385.         out    20h,al            ;8259A command reg
  386.         nop
  387.         nop
  388.         nop                ;now, ISR should be ready
  389.         in    al,20h            ;AL=mask of active INTs
  390.         or    al,al            ;test all (IRQ0 *did* EOI)
  391.         jnz    NotSafe            ;jump if active INTs
  392.  
  393. ; ------------    NOW, ENSURE THAT DOS WAS NOT INTERRUPTED
  394.  
  395.         assume    ds:nothing
  396.  
  397.         lds    bx,InDosPtr        ;now, DS:BX=InDos
  398.         mov    al,byte ptr [bx]    ;get InDos to AL
  399.         lds    bx,CritErrPtr        ;now, DS:BX=CritErr
  400.         or    al,byte ptr [bx]    ;both flags zero?
  401.         jz    DosSafe            ;YES - DOS is really idle
  402.         test    TsrMode,InInt28        ;is this an INT28h
  403.         jz    NotSafe            ;NO - not safe, should be idle
  404.         cmp    al,1            ;YES - one InDos entry only?
  405.         ja    NotSafe            ;NO - jump if more than one
  406. DosSafe:
  407.  
  408. ; ------------    CHECK TO SEE IF A PRINT SCREEN IS IN PROGRESS
  409.  
  410.         mov    ax,BiosXX
  411.         mov    ds,ax            ;move DS to BIOS extra data seg
  412.         assume    ds:BiosXX
  413.  
  414.         cmp    StatusByte,InPrtSc    ;print screen in progress?
  415.         je    NotSafe            ;YES - jump if prtsc
  416.  
  417. ; ------------    SEEMS TO BE A SAFE TIME FOR POPUP
  418.  
  419. IsSafe:        clc                ;CLC=safe to popup
  420.         jmp    short ExitSafe        ;end this then
  421.  
  422. ; ------------    APPARENTLY THIS IS JUST NOT THE TIME TO DO A POPUP
  423.  
  424. NotSafe:    stc                ;CY=don't popup now
  425.  
  426. ; ------------    RETURN TO CALLER WITH CARRY SET/CLEAR
  427.  
  428. ExitSafe:    pop    ds            ;restore regs
  429.         pop    bx
  430.         pop    ax
  431.         ret
  432. TestSafe    endp
  433.  
  434. ;==============================================================================
  435. ; OurInt08 - TSR INT08H HANDLER TO WATCH FOR HOTKEY AND SAFE POPUP TIMES
  436. ;
  437. ; CALL OldInt08
  438. ; CHECK FOR RE-ENTRANCE INTO CRITICAL INT08 CODE
  439. ; SET InInt08 FLAG
  440. ; CHECK FOR TIMEOUT BETWEEN KEYS IN HOTKEY SEQUENCE
  441. ; CHECK IF HOTKEY WAS PRESSED
  442. ; CHECK IF ALREADY InPopup OR InInt28
  443. ; CHECK IF SAFE TIME FOR SYSTEM TO POPUP
  444. ; UPDATE FLAGS AND CALL POPUP IF SAFE
  445. ; GIVE ERROR BEEP IF POPUP WAS UNSAFE FOR A LONG TIME
  446. ; RESET InInt08 FLAG
  447. ; DO IRET
  448. ;==============================================================================
  449.  
  450. ; ------------    NEAR JUMP DESTINATION FOR FAST IRET'S
  451.  
  452. Exit08:        iret                ;IRET (!)
  453.  
  454. ; ------------    ACTUAL INT08 ENTRY POINT
  455.  
  456. OurInt08    proc    far
  457.         assume    ds:nothing, es:nothing, ss:nothing
  458.  
  459.         pushf                ;simulate INT08
  460.         cli                ;in case others forgot it
  461.         call    OldInt08        ;call TSRs loaded before us
  462.  
  463. ; ------------    ENSURE NO RECURSION INTO CRITICAL INT08 CODE
  464.  
  465.         sti                ;we'll manage INTs
  466.  
  467.         test    TsrMode,InInt08        ;already in here somewhere?
  468.         jnz    Exit08            ;YES - don't re-enter
  469.         or    TsrMode,InInt08        ;tell people we are here
  470.  
  471.         push    ax            ;need a few regs in this code
  472.  
  473. ; ------------    COUNT DOWN TIME-OUT BETWEEN KEYS IN HOTKEY SEQUENCE
  474.  
  475.         test    KeyMode,InHotMatch    ;are we in a key match?
  476.         jz    TestHot08        ;NO - don't care then
  477.         dec    BetweenKeys        ;count down timeout val
  478.         jnz    TestHot08        ;jump if no timeout yet
  479.         mov    HotIndex,0        ;start match from beginning
  480.         and    KeyMode,not InHotMatch    ;just so we know it next time
  481.  
  482. ; ------------    CHECK FOR POSSIBLE POPUP ACTIONS
  483.  
  484. TestHot08:    test    KeyMode,HotKeyOn    ;has hotkey been pressed?
  485.         jz    ExitInt08        ;NO - jump if no fun here
  486.  
  487.         test    TsrMode,InInt28 OR InPopup
  488.         jnz    ExitInt08        ;jmp if not alr in business
  489.  
  490. ; ------------    HOTKEY PRESSED, CHECK TO SEE IF IT IS SAFE TO POPUP
  491.  
  492.         cmp    SafeWait,0        ;first time we find hotkey?
  493.         ja    TestSafe08        ;NO - wait has alr been set
  494.         mov    SafeWait,MaxWait    ;# ticks to wait at most
  495.  
  496. TestSafe08:    call    TestSafe        ;now, CY clear if popup is safe
  497.         jc    NotSafe08        ;jump if popup is bad idea
  498.  
  499. ; ------------    SEEMS SAFE TO POPUP AT THIS TIME, SO DO!
  500.  
  501.         xor    al,al            ;fast zero
  502.         mov    SafeWait,al        ;don't count any more
  503.         and    KeyMode,not HotKeyOn    ;clear hotkey status
  504.         or    TsrMode,InPopup        ;tell'em we enter popup routine
  505.         and    TsrMode,not InInt08    ;OK to enter critical INT08
  506.         call    InitPopup        ;do actual popup
  507.         or    TsrMode,InInt08        ;back in INT08 code here
  508.         and    TsrMode,not InPopup    ;not in popup code any more
  509.         mov    SafeWait,al        ;in case of hotkey during popup
  510.         and    KeyMode,not HotKeyOn    ;clear hotkey status
  511.  
  512.         jmp    short ExitInt08        ;finally done
  513.  
  514. ; ------------    UNSAFE POPUP TIME, COUNT DOWN SafeWait
  515.  
  516. NotSafe08:    dec    SafeWait        ;count down waiter
  517.         jnz    ExitInt08         ;jump if still no timeout
  518.  
  519. ; ------------    NO SAFE TIMES FOUND FOR QUITE SOME TIME, ERROR
  520.  
  521.         and    KeyMode,not HotKeyOn    ;might as well clear hotkey
  522.         call    ErrBeep            ;do an error beep
  523.  
  524. ; ------------    NORMAL INT08H EXIT, RESET InInt08
  525.  
  526. ExitInt08:    pop    ax            ;restore regs used
  527.         and    TsrMode,not InInt08    ;clear that flag
  528.         iret                ;straight back
  529. OurInt08    endp
  530.  
  531. ;==============================================================================
  532. ; OurInt09 - TSR INT09H HANDLER TO WATCH FOR HOTKEY
  533. ;
  534. ; SAVE SCAN CODE
  535. ; CALL OldInt09
  536. ; CHECK FOR RECURSION INTO CRITICAL INT09 CODE
  537. ; SET InInt09 FLAG
  538. ; CHECK IF HOTKEY ALREADY SET
  539. ; DETERMINE HOTKEY TYPE (SHIFT STATE OR KEY SEQENCE)
  540. ; CHECK SHIFT STATE IF HotIsShift
  541. ; COMPARE FOR KEY MATCH IF (NOT HotIsShift)
  542. ; SET HotKeyOn IF HOTKEY PRESSED
  543. ; RESET InInt09 FLAG
  544. ; DO IRET
  545. ;==============================================================================
  546.  
  547. ; ------------    NEAR JUMP DESTINATION FOR EARLY EXITS
  548.  
  549. Exit09:        pop    bx            ;restore regs
  550.         pop    ax
  551.         iret                ;flags restored from stack
  552.  
  553. ; ------------    ACTUAL INT09 ENTRY POINT
  554.  
  555. OurInt09    proc    far
  556.         assume    ds:nothing, es:nothing, ss:nothing
  557.  
  558.         push    ax            ;save regs used
  559.         push    bx
  560.  
  561. ; ------------    READ SCAN CODE, IN CASE SEQUENCE MATCHING SELECTED
  562.  
  563.         in    al,KbData        ;Al=key, preserved by BIOS
  564.  
  565. ; ------------    CALL BIOS TO PERFORM IT'S DUTIES
  566.  
  567.         pushf                ;simulate INT (CLI alr set)
  568.         cli                ;in case others forgot it
  569.         call    OldInt09        ;call BIOS/earlier TSRs
  570.  
  571. ; ------------    ENSURE NO RECURSION INTO CRITICAL INT09 CODE
  572.  
  573.         sti                ;we'll manage INTs
  574.  
  575.         test    TsrMode,InInt09        ;alr in business?
  576.         jnz    Exit09            ;YES - skip test till clear
  577.         or    TsrMode,InInt09        ;tell them we arrived here
  578.  
  579. ; ------------    DETERMINE HOT KEY TYPE SELECTED
  580.  
  581.         test    KeyMode,HotKeyOn    ;already hotkey there?
  582.         jnz    ExitInt09        ;YES - no double hotkeys here
  583.  
  584.         test    KeyMode,HotIsShift    ;shift state type hotkey?
  585.         jz    CompSeq09        ;NO - go compare sequence
  586.  
  587. ; ------------    COMPARE CURRENT SHIFT STATUS AGAINST HOTKEY
  588.  
  589.         push    ds            ;save current ds
  590.         mov    ax,BiosData        ;move DS to BIOS data seg
  591.         mov    ds,ax            ;DS can now access keyb vars
  592.         assume    ds:BiosData        ;tell MASM about our DS
  593.         mov    al,KbFlag        ;get BIOS shift state bits
  594.         pop    ds            ;restore
  595.         assume    ds:nothing        ;last thing we know about him
  596.  
  597.         and    al,HotKeyShift        ;isolate relevant bits
  598.         cmp    al,HotKeyShift        ;our shift state in effect?
  599.         jne    ExitInt09        ;NO - not that shift state
  600.         or    KeyMode,HotKeyOn    ;YES - flag hotkey
  601.         jmp    short ExitInt09        ;now we can be proud to leave
  602.  
  603. ; ------------    MATCH KEY IN SCAN CODE SEQUENCE
  604.  
  605. CompSeq09:    mov    bl,HotIndex        ;next scan code to match
  606.         xor    bh,bh            ;must be word
  607.         cmp    al,HotKeySeq[bx]    ;does key match?
  608.         je    HotMatch09        ;YES - jump if match
  609.         mov    HotIndex,bh        ;search from start next time
  610.         and    KeyMode,not InHotMatch    ;current no match
  611.         jmp    short ExitInt09        ;now end this
  612.  
  613. ; ------------    KEY MACTHED NEXT SCAN CODE IN HotKeySeq
  614.  
  615. HotMatch09:    inc    bl            ;new code at next pass
  616.         cmp    bl,HotKeyLen        ;did we match whole sequence?
  617.         jae    HotHit09         ;YES - jump if full sequence
  618.         mov    HotIndex,bl        ;NO - save new count
  619.         mov    BetweenKeys,KeyTimeOut    ;reset counter between keys
  620.         or    KeyMode,InHotMatch    ;we are in a match now
  621.         jmp    short ExitInt09        ;time to end this
  622.  
  623. ; ------------    KEY MATCHED ALL SCAN CODES IN HOTKEY SEQUENCE
  624.  
  625. HotHit09:    or    KeyMode,HotKeyOn    ;say hotkey was pressed
  626.         mov    HotIndex,bh        ;match 1st code next time
  627.         and    KeyMode,not InHotMatch    ;that's the end of a match
  628.  
  629. ; ------------    EXIT FROM INT09H, RESET InInt09 FLAG
  630.  
  631. ExitInt09:    and    TsrMode,not InInt09    ;tell'em we left this code
  632.         pop    bx            ;restore regs
  633.         pop    ax
  634.         iret                ;flags restored from stack
  635. OurInt09    endp
  636.  
  637. ;==============================================================================
  638. ; OurInt13 - SET InInt13 FLAG TO SAY THAT WE ARE IN AN INT13H
  639. ;==============================================================================
  640.  
  641. OurInt13    proc    far
  642.         assume    ds:nothing, es:nothing, ss:nothing
  643.  
  644.         pushf                ;save flags we use
  645.         or    TsrMode,InInt13        ;remember we are in BIOS now
  646.         popf                ;restore flags
  647.  
  648.         pushf                ;simulate INT13
  649.         cli                ;just in case others forgot
  650.         call    OldInt13        ;let BIOS handle it all
  651.  
  652.         pushf                ;BIOS uses flag return
  653.         and    TsrMode, not InInt13    ;tell people we left INT13h
  654.         popf
  655.  
  656.         ret    2            ;throw flags off stack
  657. OurInt13    endp
  658.  
  659. ;==============================================================================
  660. ; OurInt16 - TSR INT16H HANDLER, INT28 CHAIN INTERFACE
  661. ;
  662. ; INPUT:    AX = GetId
  663. ; OUTPUT:    AX = MyId
  664. ; REGS:        AX LOST, ALL OTHERS PRESERVED
  665. ; DESCRIPTION:    DETERMINE IF TSR WITH THIS ID IS ALREADY IN MEMORY
  666. ;
  667. ; INPUT:    AH = 00
  668. ; OUTPUT:    AX = NEXT KEY FROM BUFFER
  669. ; REGS;        AX LOST, ALL OTHERS PRESERVED
  670. ; DESCRIPTION:    RETURN A KEY FROM KEYBOARD BUFFER, WAIT TILL KEY IS PRESSED
  671. ;
  672. ; INPUT:    AH = 02
  673. ; OUTPUT:    AX = KEY FROM BUFFER IN ANY
  674. ;        ZF = NO KEYS IN BUFFER (AX PRESERVED)
  675. ;        NZ = KEY IN BUFFER (RETURNED IN AX, KEY STILL IN BUFFER)
  676. ; DESCRIPTION:    CHECK BUFFER FOR ANY PENDING KEYS, RETURN KEY IF ANY
  677. ;
  678. ; NOTE:    ALL OTHER AX REQUEST CODES ARE PASSED ON TO BIOS INT16H HANDLER.
  679. ;
  680. ; NOTE:    DURING INT28 POPUP (InPopup AND NOT InDosClr) FUNCTIONS AH=0 AND
  681. ;    AH=1 WILL ISSUE INT28, UNLESS InDos HAS FROM VALUE AT POPUP OR
  682. ;    CritErr HAS BEEN SET.
  683. ;==============================================================================
  684.  
  685. OurInt16    proc    far
  686.         assume    ds:nothing, es:nothing, ss:nothing
  687.  
  688.         sti                ;we'll manage INTs
  689.         pushf                ;save callers flags
  690.         cmp    ax,GetId        ;return ID request?
  691.         jne    NotId16            ;NO - jump if not
  692.  
  693. ; ------------    TSR DIAGNOSTIC REQUEST, RETURN SPECIAL VALUE TO SAY WE ARE HERE
  694.  
  695.         mov    ax,MyId            ;ID val returned in AX
  696.         popf                ;restore flags
  697.         iret                ;return to caller
  698.  
  699. ; ------------    PASS CONTROL TO BIOS, FLAGS ON STACK
  700.  
  701. GoBios16:    popf                ;restore flags at INT time
  702.         jmp    OldInt16        ;continue in the woods
  703.  
  704. ; ------------    REGULAR BIOS INT16 REQUEST, CHECK FOR ANY FANCY ACTIONS
  705.  
  706. NotId16:    test    TsrMode,InPopup        ;are we in a popup?
  707.         jz    GoBios16        ;NO - leave rest with BIOS
  708.         test    TsrMode,InDosClr    ;InDos clear at popup?
  709.         jnz    GoBios16        ;YES - no need to signal INT28
  710.  
  711.         popf                ;restore original flags
  712.         push    bx            ;we need a few regs here
  713.         push    cx
  714.         push    si
  715.         push    ds
  716.         pushf                ;original flags back on stack
  717.  
  718. ; ------------    GET REQUEST CODE TO BH ENHANCED BIT TO BL
  719.  
  720.         mov    bh,ah            ;BH=function request code
  721.         and    bh,not 10h        ;zap enhanced kybd bit
  722.         cmp    bh,1            ;any function above 1?
  723.         ja    ExitBios16        ;YES - leave rest with BIOS
  724.  
  725.         mov    bl,ah            ;BL used for enhanced bit
  726.         and    bl,10h            ;BL=value of enhanced bit
  727.  
  728. ; ------------    GET InDos To CL, CritErr to CH, SETUP REGS
  729.  
  730.         assume    ds:nothing
  731.  
  732.         lds    si,InDosPtr        ;DS:[SI]=InDos
  733.         mov    cl,byte ptr [si]    ;CL=InDos value
  734.         lds    si,CritErrPtr        ;ES:[SI]=CritErr
  735.         mov    ch,byte ptr [si]    ;CH=CritErr value
  736.  
  737.         mov    si,ax            ;save AX call value
  738.  
  739.         mov    ax,cs            ;move DS here, now we got it
  740.         mov    ds,ax
  741.         assume    ds:Cseg            ;everybody should know
  742.  
  743. ; ------------    CHECK KEYBOARD BUFFER, ORIGINAL FLAGS ON STACK
  744.  
  745. Wait16:        mov    ah,1            ;AH=1=test buffer status
  746.         or    ah,bl            ;maintain enhanced bit value
  747.  
  748.         popf                ;restore original flags
  749.         pushf                ;simulate INT
  750.         cli                ;in case others forgot
  751.         call    OldInt16        ;now, ZF set if no keys
  752.         pushf                ;save result flags
  753.         jnz    TestSkip16        ;jump if a key was found
  754.  
  755. ; ------------    NO KEY FOUND, CALL INT28 IF DOS InDos ALLOWS
  756.  
  757.         cmp    cx,0001h        ;CritErr=0, InDos=1 ?
  758.         jne    NextKey16        ;NO - wait for next key
  759.         or    TsrMode,In28Call    ;tell people we called this INT
  760.         int    28h            ;now take your chance
  761.         and    TsrMode,not In28Call    ;end of that call
  762.  
  763. ; ------------    TEST BUFFER AGAIN IF INT16.00, IRET IF INT16.01
  764.  
  765. NextKey16:    or    bh,bh            ;is this a wait for key?
  766.         jz    Wait16            ;YES - then go wait for it!
  767.         mov    ax,si            ;restore original AX contents
  768.         jmp    short Exit16        ;NO - exit with status we got
  769.  
  770. ; ------------    KEY IN BUFFER, IF CTRL-C WE MAY HAVE TO SKIP IT, FLAGS ON STACK
  771.  
  772. TestSkip16:    cmp    al,3            ;is this Ctrl-C?
  773.         jne    TestExit16        ;NO - determine exit method
  774.         test    cx,not 0001h        ;anything but InDos=1?
  775.         jz    TestExit16        ;NO - determine exit method
  776.  
  777. ; ------------    SKIP CTRL-C IN KEYBOARD BUFFER
  778.  
  779.         mov    ah,bl            ;AH=0 + enhanced bit
  780.         popf                ;restore original INTs
  781.         pushf                ;save again
  782.         pushf                ;simulate INT
  783.         cli                ;simulate properly!
  784.         call    OldInt16        ;now, key should be gone
  785.         jmp    short Wait16        ;do as if nothing had happened
  786.  
  787. ; ------------    KEY IN AX, IRET IF INT16.01, LEAVE WITH BIOS IF INT16.00
  788.  
  789. TestExit16:    or    bh,bh            ;is this a wait for key?
  790.         jnz    Exit16            ;NO - do fast return
  791.         mov    ax,si            ;YES - restore AX code
  792.  
  793. ; ------------    PASS CONTROL TO BIOS, FLAGS & REGS ON STACK
  794.  
  795.         assume    ds:nothing
  796.  
  797. ExitBios16:    popf                ;restore work flags
  798.         pop    ds            ;restore regs
  799.         pop    si
  800.         pop    cx
  801.         pop    bx
  802.         cli                ;should look like an INT
  803.         jmp    OldInt16        ;leave rest with BIOS
  804.  
  805. ; ------------    RETURN FROM INT16, FLAGS & REGS ON STACK
  806.  
  807.         assume    ds:nothing
  808.  
  809. Exit16:        popf                ;restore proper flags
  810.         pop    ds            ;restore regs
  811.         pop    si
  812.         pop    cx
  813.         pop    bx
  814.         ret    2            ;IRET, without flags restore
  815.  
  816. OurInt16    endp
  817.  
  818. ;==============================================================================
  819. ; OurInt21 - INT21 FILTER TO THROW DANGEROUS DOS CALLS ON CRITICAL STACK
  820. ;
  821. ; CHECK IF InPopup AND InDosClr
  822. ; CHECK FUNCTION USES CONSOLE STACK
  823. ; SET CritErr IN DOS IF CONSOLE STACK USED
  824. ; CALL OldInt21
  825. ; RESTORE CritErr IF CRITICAL STACK USED
  826. ;==============================================================================
  827.  
  828. OurInt21    proc    far
  829.         assume    ds:nothing, es:nothing
  830.  
  831.         pushf                ;save calling flags
  832.         sti
  833.  
  834.         test    TsrMode,InPopup        ;are we in a popup?
  835.         jz    GoDos21            ;NO - don't worry then
  836.         test    TsrMode,InDosClr    ;console stack idle?
  837.         jnz    GoDos21            ;YES - nothing fancy then
  838.  
  839. ; ------------    THIS IS 2ND CALL INTO DOS, SEE IF USING CONSOLE STACK
  840.  
  841.         cmp    ah,0ch            ;any function 00-0C?
  842.         jbe    UseCrit21        ;YES - use critical stack
  843.         test    TsrMode,NewDos        ;NO - is this DOS 3.x?
  844.         jnz    GoDos21            ;YES - no other to worry about
  845.         cmp    ah,50h            ;set PSP function?
  846.         je    UseCrit21        ;YES - use critical stack
  847.         cmp    ah,51h            ;get PSP function?
  848.         jne    GoDos21            ;NO - leave it with DOS
  849.  
  850. ; ------------    FORCE USE OF CRITICAL STACK FOR THIS CALL
  851.  
  852. UseCrit21:    assume    ds:nothing        ;nothing to say about DS
  853.  
  854.         push    si            ;save regs
  855.         push    ds
  856.         lds    si,CritErrPtr        ;now, DS:[SI]=InDos
  857.         mov    byte ptr [si],-1    ;FF=use crit stack now
  858.         pop    ds            ;restore regs
  859.         pop    si
  860.  
  861.         popf                ;retsore flags setting
  862.         pushf                ;simulate INT
  863.         cli                ;in case others forgot
  864.         call    OldInt21        ;flags already on stack
  865.  
  866.         push    si            ;save regs
  867.         push    ds
  868.         lds    si,CritErrPtr        ;now, DS:[SI]=InDos
  869.         mov    byte ptr [si],0        ;0=back to default stack
  870.         pop    ds            ;restore regs
  871.         pop    si
  872.  
  873.         ret    2            ;IRET throw old flags
  874.  
  875. ; ------------    PASS CONTROL TO DOS, FLAGS ON STACK
  876.  
  877. GoDos21:    popf                ;restore original flags
  878.         cli                ;just in case someone forgot
  879.         jmp    OldInt21        ;let DOS handle the rest
  880. OurInt21    endp
  881.  
  882. ;==============================================================================
  883. ; OurInt24 - SAFE DOS CRITICAL ERROR HANDLER
  884. ; IF DOS 3.X, FAIL THE SYSTEM CALL
  885. ; IF NOT DOS 3.X, IGNORE ERROR
  886. ;==============================================================================
  887.  
  888. OurInt24    proc    far
  889.         assume    ds:nothing, es:nothing, ss:nothing
  890.         mov    al,3            ;AL=3=fail system call
  891.         test    TsrMode,NewDos        ;are we using DOS 3.x?
  892.         jnz    Exit24            ;YES - OK to use AL=3
  893.         xor    al,al            ;NO - have to ignore err then
  894. Exit24:        iret                ;return to DOS
  895. OurInt24    endp
  896.  
  897. ;==============================================================================
  898. ; OurInt28 - TSR INT28H HANDLER, ALLOWS POPUP DURING DOS IDLE CALLS
  899. ;
  900. ; CALL OldInt28
  901. ; CHECK FOR RECURSION INTO CRITICAL INT28 CODE (& OTHER INTs AS WELL)
  902. ; SET InInt28 FLAG
  903. ; CHECK FOR HOTKEY
  904. ; CHECK IF SAFE TO POPUP
  905. ; DO POPUP IF SAFE AT THIS TIME
  906. ; RESET InInt28 FLAG
  907. ; DO IRET
  908. ;==============================================================================
  909.  
  910. ; ------------    NEAR JUMP DESTINATION FOR FAST IRET'S
  911.  
  912. Exit28:        iret                ;IRET (!)
  913.  
  914. ; ------------    ACTUAL INT28 ENTRY POINT
  915.  
  916. OurInt28    proc    far
  917.         assume    ds:nothing, es:nothing, ss:nothing
  918.  
  919.         pushf
  920.         cli                ;in case others forgot it
  921.         call    OldInt28        ;call TSRs loaded before this
  922.  
  923. ; ------------    ENSURE NO RECURSION ON CRITICAL INT28 CODE
  924.  
  925.         sti                ;we'll manage INT's after this
  926.         test    TsrMode,InInt08 OR InInt28 OR In28Call OR InPopup
  927.         jnz    Exit28            ;exit fast if already going
  928.         or    TsrMode,InInt28        ;tell'em we are here
  929.  
  930. ; ------------    CHECK FOR POSSIBLE POPUP ACTIONS
  931.  
  932.         test    KeyMode,HotKeyOn    ;any hotkeys pressed?
  933.         jz    ExitInt28        ;NO - don't check any more then
  934.  
  935. ; ------------    HOTKEY WAS PRESSED, ENSURE IT'S SAFE TO DO POPUP
  936.  
  937.         call    TestSafe        ;now, CY clear if popup is OK
  938.         jc    ExitInt28        ;jump if not to popup
  939.  
  940. ; ------------    SEEMS OK TO DO POPUP, SO DO!
  941.  
  942.         and    KeyMode,not HotKeyOn    ;clear hotkey status
  943.         or    TsrMode,InPopup        ;tell'em we enter popup routine
  944.         and    TsrMode,not InInt28    ;OK to enter critical INT28
  945.         call    InitPopup        ;then do popup
  946.         or    TsrMode,InInt28        ;back in INT28 code here
  947.         and    TsrMode,not InPopup    ;not in popup code any more
  948.         and    KeyMode,not HotKeyOn    ;clear hotkeys during popup
  949.  
  950. ; ------------    NORMAL INT28H EXIT, RESET InInt28 FLAG
  951.  
  952. ExitInt28:    and    TsrMode,not InInt28    ;tell'em we left this code
  953.         iret                ;we have nothing more to say
  954. OurInt28    endp
  955.  
  956. ;==============================================================================
  957. ; NopInt - DUMMY IRET INSTRUCTION USED BY EMPTY INT HANDLERS
  958. ;==============================================================================
  959.  
  960. NopInt:        iret                ;immediate return
  961.  
  962. ;==============================================================================
  963. ; InitPopup - PREPARES SYSTEM FOR POPUP, THEN CALLS Popup, THEN RESTORES
  964. ;
  965. ; ESTABLISH INTERNAL WORK STACK
  966. ; SAVE CPU REGS
  967. ; UPDATE InDosClr FLAG WITH CURRENT VALUE OF InDos
  968. ; SAVE PROCESS RELATED SYSTEM INFO
  969. ; SAVE USER INTERRUPT VECTORS
  970. ; INSERT SAFE USER INTERRUPT VECTORS
  971. ; CALL POPUP ROUTINE
  972. ; RESTORE USER INTERRUPT VECTORS
  973. ; RESTORE PROCESS AND SYSTEM INFO
  974. ; CLEAR InDosClr FLAG TO PREVENT UNSAFE INT28 CALLs
  975. ; RESTORE CPU REGS
  976. ;==============================================================================
  977.  
  978. InitPopup    proc    near
  979.         assume    ds:nothing, es:nothing, ss:nothing
  980.  
  981. ; ------------    SWITCH TO PSP INTERNAL STACK
  982.  
  983.         mov    OldSS,ss        ;save current stack frame
  984.         mov    OldSP,sp
  985.  
  986.         cli                ;always CLI for the old chips
  987.         mov    ss,OurSS        ;move SS here
  988.         mov    sp,OurSP        ;move SP into position
  989.         sti                ;OK guys
  990.  
  991. ; ------------    SAVE ALL REGS
  992.  
  993.         push    ax
  994.         push    bx
  995.         push    cx
  996.         push    dx
  997.         push    bp
  998.         push    si
  999.         push    di
  1000.         push    ds
  1001.         push    es
  1002.  
  1003.         mov    ax,cs
  1004.         mov    ds,ax            ;mov DS here
  1005.         assume    ds:Cseg            ;tell MASM that
  1006.  
  1007. ; ------------    TAG VALUE OF InDos FLAG AT TIME OF POPUP
  1008.  
  1009.         or    TsrMode,InDosClr    ;assume InDos=0
  1010.         les    si,InDosPtr        ;now, ES:[SI]=InDos
  1011.         cmp    byte ptr es:[si],1    ;InDos set? (>2 impossible)
  1012.         jb    InDosSaved        ;NO - jump if all clear DOS
  1013.         and    TsrMode,not InDosClr    ;clear flag for popup InDos
  1014. InDosSaved:
  1015.  
  1016. ; ------------    SAVE DOS 3.X EXTENDED ERROR INFO
  1017.  
  1018.         test    TsrMode,NewDos        ;really DOS 3.x?
  1019.         jz    Dos3Saved        ;NO - jump if not 3.x
  1020.  
  1021.         mov    ah,59h            ;to get err info from DOS
  1022.         xor    bx,bx            ;BX must be zero
  1023.         push    ds            ;save DS (killed by DOS)
  1024.         int    21h            ;ext err info in AX,BX,CX
  1025.         pop    ds            ;restore
  1026.         mov    OldExtErr[0],ax        ;save
  1027.         mov    OldExtErr[2],bx
  1028.         mov    OldExtErr[4],cx
  1029.  
  1030. Dos3Saved:
  1031.  
  1032. ; ------------    SAVE CURRENT BREAK STATE, RELAX BREAK CHECKING
  1033.  
  1034.         mov    ax,3302h        ;to swap DL with BREAK value
  1035.         xor    dl,dl            ;DL=0=relax checking
  1036.         int    21h            ;current level in DL
  1037.         mov    OldBreak,dl        ;save current level
  1038.  
  1039. ; ------------    SAVE CURRENT USER INT VECTORS
  1040.  
  1041.         mov    ax,351bh        ;BIOS ctrl-break int
  1042.         int    21h            ;ES:BX=vector
  1043.         mov    OldInt1BOff,bx        ;save it
  1044.         mov    OldInt1BSeg,es
  1045.  
  1046.         mov    ax,351ch        ;BIOS timer tick
  1047.         int    21h            ;ES:BX=vector
  1048.         mov    OldInt1COff,bx        ;save it
  1049.         mov    OldInt1CSeg,es
  1050.  
  1051.         mov    ax,3523h        ;DOS ctrl-C
  1052.         int    21h            ;ES:BX=vector
  1053.         mov    OldInt23Off,bx        ;save it
  1054.         mov    OldInt23Seg,es
  1055.  
  1056.         mov    ax,3524h        ;DOS crit err handler
  1057.         int    21h            ;ES:BX=vector
  1058.         mov    OldInt24Off,bx        ;save it
  1059.         mov    OldInt24Seg,es
  1060.  
  1061. ; ------------    INSERT DUMMY IRET INTO DANGEROUS VECTORS
  1062.  
  1063.         mov    dx,offset NopInt    ;now, DS:DX=dunny iret
  1064.         mov    ax,251bh        ;BIOS ctrlk-break handler
  1065.         int    21h            ;set to IRET
  1066.         mov    ax,251ch        ;BIOS timer tick
  1067.         int    21h            ;set to IRET
  1068.         mov    ax,2523h        ;DOS ctrl-C handler
  1069.         int    21h            ;set to IRET
  1070.  
  1071. ; ------------    ESTABLISH SAFE CRITICAL ERROR HANDLER
  1072.  
  1073.         mov    dx,offset OurInt24    ;now, DS:DX=safe crit err
  1074.         mov    ax,2524h        ;to set crit err handler
  1075.         int    21h
  1076.  
  1077. ; ------------    SAVE CURRENT DTA AREA, SET OUR DEFAULT DTA
  1078.  
  1079.         mov    ah,2fh            ;to obtain current DTA from DOS
  1080.         int    21h            ;DTA addr now in ES:BX
  1081.         mov    OldDTAOff,bx        ;save it
  1082.         mov    OldDTASeg,es
  1083.  
  1084.         push    ds            ;save DS for a while
  1085.         lds    dx,OurDTA        ;DS:DX=our DTA addr
  1086.         mov    ah,1ah            ;to set DTA via DOS
  1087.         int    21h            ;set that addr
  1088.         pop    ds            ;restore DS
  1089.  
  1090. ; ------------    SAVE CURRENT PSP, ESTABLISH OURS INSTEAD
  1091.  
  1092.         mov    ax,5100h        ;to get PSP from DOS
  1093.         int    21h            ;current PSP now in BX
  1094.         mov    OldPSP,bx        ;save it
  1095.         mov    bx,OurPSP        ;het our PSP instead
  1096.         mov    ax,5000h        ;to set our PSP
  1097.         int    21h
  1098.  
  1099. ; ------------    CALL USER POPUP ROUTINE
  1100.  
  1101.         call    Popup            ;finally!
  1102.  
  1103. ; ------------    RESTORE TO SAVED CURRENT PROCESS
  1104.  
  1105.         mov    bx,OldPSP        ;new current process in BX
  1106.         mov    ax,5000h        ;to set PSP via DOS
  1107.         int    21h            ;restore original PSP
  1108.  
  1109. ; ------------    RESTORE SAVED DTA
  1110.  
  1111.         push    ds            ;save DS for a while
  1112.         lds    dx,OldDTA        ;DS:DX=our DTA addr
  1113.         mov    ah,1ah            ;to set DTA via DOS
  1114.         int    21h            ;set that addr
  1115.         pop    ds            ;restore DS
  1116.  
  1117. ; ------------    RESTORE SAVED INTERRUPT VECTORS
  1118.  
  1119.         push    ds            ;save for a while
  1120.         assume    ds:nothing        ;be careful about MASM
  1121.  
  1122.         lds    dx,OldInt1B        ;BIOS ctrl-break handler
  1123.         mov    ax,251bh
  1124.         int    21h
  1125.  
  1126.         lds    dx,OldInt1C        ;BIOS timer tick
  1127.         mov    ax,251ch
  1128.         int    21h
  1129.  
  1130.         lds    dx,OldInt23        ;DOS ctrl-C
  1131.         mov    ax,2523h
  1132.         int    21h
  1133.  
  1134.         lds    dx,OldInt24        ;DOS crit err handler
  1135.         mov    ax,2524h
  1136.         int    21h
  1137.  
  1138.         pop    ds            ;restore data seg DS
  1139.         assume    ds:Cseg
  1140.  
  1141. ; ------------    RESTORE SAVED BREAK CHECKING LEVEL
  1142.  
  1143.         mov    ax,3301h        ;to set break check level
  1144.         mov    dl,OldBreak        ;get saved break state
  1145.         int    21h
  1146.  
  1147. ; ------------    RESTORE DOS 3.X SPECIFIC SYSTEM INFO
  1148.  
  1149.         test    TsrMode,NewDos        ;using DOS 3.x
  1150.         jz    Dos3Restored        ;NO - jump if old DOS 2
  1151.         mov    dx,offset OldExtErr    ;DS:DX=3 words of ext err
  1152.         mov    ax,5d0ah        ;to set ext err info
  1153.         int    21h
  1154. Dos3Restored:
  1155.  
  1156. ; ------------    RESET InDosSet FLAG VALUE TO PREVENT UNSAFE INT28
  1157.  
  1158.         or    TsrMode,InDosClr    ;now we only care that InDos=0
  1159.  
  1160. ; ------------    RESTORE USER REGS
  1161.  
  1162.         pop    es
  1163.         pop    ds
  1164.         pop    di
  1165.         pop    si
  1166.         pop    bp
  1167.         pop    dx
  1168.         pop    cx
  1169.         pop    bx
  1170.         pop    ax
  1171.         assume    ds:nothing
  1172.  
  1173. ; ------------    RETURN TO USER STACK
  1174.  
  1175.         cli                ;always CLI for the old chips
  1176.         mov    ss,OldSS        ;restore SS
  1177.         mov    sp,OldSP        ;restore SP
  1178.         sti                ;OK guys
  1179.  
  1180.         ret
  1181. InitPopup    endp
  1182.  
  1183. ;==============================================================================
  1184. ; DATA FOR POPUP ROUTINE
  1185. ;==============================================================================
  1186.  
  1187. DosReadMsg    db    13,10,'Reading DOS CON (press <Enter> to terminate)',13,10
  1188. DosReadLen    equ    $-DosReadMsg
  1189.  
  1190. BiosReadMsg    db    'Reading BIOS keyboard (press any key... )',8,8
  1191. BiosReadLen    equ    $-BiosReadMsg
  1192.  
  1193. DoneMsg        db    ' key pressed, exit from TSR DEMO)',13,10
  1194. DoneLen        equ    $-DoneMsg
  1195.  
  1196. Scratch        db    80 dup (?)
  1197.  
  1198. ;==============================================================================
  1199. ; Popup - POPUP USER ROUTINE
  1200. ;
  1201. ; ALL REGISTERS EXCEPT SS:SP AND DS MAY BE CHANGED.
  1202. ; DS IS PRESET TO THE TSR DATA SEGMENT.
  1203. ;
  1204. ; NOTE:    UPON ENTRY TO THIS ROUTINE ALL DOS FUNCTIONS MAY BE CALLED.
  1205. ;    IF POPUP WAS DONE ON INT28, WITH CritErr==1, ALL DOS FUNCTIONS
  1206. ;    THAT WOULD NORMALLY USE THE CONSOLE STACK, WILL GO TO THE CRITICAL
  1207. ;    STACK, HENCE PREVENTING FURTHER POPUP DURING THE DOS CALL.
  1208. ;    (HOWEVER, MOST TSRs WOULD NOT POPUP ANYWAY, SINCE InDos==2).
  1209. ;
  1210. ;    ADDRESSES OF THE InDos AND CritErr ARE STORED IN THE DOUBLE WORDS
  1211. ;    InDosPtr AND CritErrPtr.
  1212. ;
  1213. ;    AT ENTRY CritErr FLAG IS 0 (ZERO), InDos NO GREATER THAN 1 (ONE).
  1214. ;==============================================================================
  1215.  
  1216. Popup        proc    near
  1217.         assume    ds:Cseg, es:nothing, ss:nothing
  1218.  
  1219.         mov    ah,40h            ;DOS write handle
  1220.         mov    bx,1            ;standard output handle
  1221.         mov    dx,offset DosReadMsg    ;DS:DX=str to write
  1222.         mov    cx,DosReadLen        ;CX=# chars to write
  1223.         int    21h            ;output that string
  1224.  
  1225.         mov    ah,3fh            ;DOS read handle
  1226.         xor    bx,bx            ;standard input handle
  1227.         mov    dx,offset Scratch    ;scratch buf for key
  1228.         mov    cx,80            ;read till CR hit
  1229.         int    21h
  1230.  
  1231.         mov    ah,40h            ;read from BIOS msg
  1232.         mov    bx,1
  1233.         mov    dx,offset BiosReadMsg
  1234.         mov    cx,BiosReadLen
  1235.         int    21h
  1236.  
  1237.         xor    ah,ah            ;to let BIOS wait for key
  1238.         int    16h            ;now, key was pressed
  1239.  
  1240.         mov    ah,40h            ;write confirm msg
  1241.         mov    bx,1
  1242.         mov    dx,offset DoneMsg
  1243.         mov    cx,DoneLen
  1244.         int    21h
  1245.  
  1246.         ret
  1247. Popup        endp
  1248.  
  1249. ;==============================================================================
  1250. ; TSR IRON CURTAIN - HE WHO CROSSES THIS CURTAIN WILL BE GONE AFTER TSR!
  1251. ;==============================================================================
  1252.  
  1253. TsrCurtain:                    ;TSR memory break
  1254.  
  1255. ;==============================================================================
  1256. ; NON-RESIDENT MESSAGES FOR INIT
  1257. ;==============================================================================
  1258.  
  1259. BannerMsg    label    byte
  1260. db    13,10
  1261. db    '<<<<<<  TSR DEMO  >>>>>>',13,10
  1262. db    '   Thomas Brandenborg',13,10
  1263. db    '      Version 2.00',13,10,10
  1264. db    '$'
  1265.  
  1266. FirstMsg    label    byte
  1267. db    'Pop up routine installed resident.',13,10
  1268. db    '$'
  1269.  
  1270. SecondMsg    label    byte
  1271. db    'TSR DEMO already loaded.',13,10
  1272. db    '$'
  1273.  
  1274. HotKeyMsg    label    byte
  1275. db    'Hit <Left Shift> twice to pop up!',13,10,10
  1276. db    '$'
  1277.  
  1278. Dos1Msg    label    byte
  1279. db    'OOPS!',7,13,10
  1280. db    'Must use DOS release 2.00 or later!',13,10,10
  1281. db    '$'
  1282.  
  1283. BadDosMsg    label    byte
  1284. db    'OOPS!',7,13,10
  1285. db    'Did not recognize DOS version!',13,10,10
  1286. db    '$'
  1287.  
  1288. ; ------------    DOS ERROR LEVEL EXIT CODES
  1289.  
  1290. xOk        equ    0            ;normal, OK exit
  1291. xSecond        equ    1            ;TSR already loaded
  1292. xBadDos        equ    2            ;CritErr flag not found
  1293.  
  1294. ;==============================================================================
  1295. ; Init - INITIALIZE TSR APPLICATION, ENTERED UPON DOS LOAD
  1296. ; DISPLAY BANNER, INITIALIZE SYSTEM DATA, CHECK IF ALREADY LOADED,
  1297. ; HOOK INTO INTERRUPT CHAIN, TERMINATE, BUT STAY RESIDENT.
  1298. ;==============================================================================
  1299.  
  1300. Init        proc    near
  1301.         assume    ds:Cseg, es:nothing, ss:nothing
  1302.  
  1303.         mov    dx,offset BannerMsg
  1304.         mov    ah,9
  1305.         int    21h            ;display programme banner
  1306.  
  1307. ; ------------    USE INT16H DIAGNOSTIC TO SEE IF TSR ALREADY INSTALLED
  1308.  
  1309.         mov    ax,GetId        ;INT16h diagnostic request
  1310.         int    16h            ;now, AX=MyId if installed
  1311.         cmp    ax,MyId            ;TSR already installed?
  1312.         jne    CheckDos        ;NO - jump if not installed
  1313.  
  1314. ; ------------    TSR ALREADY INSTALLED, DISPLAY MSG, EXIT
  1315.  
  1316.         mov    dx,offset SecondMsg
  1317.         mov    ah,9
  1318.         int    21h                ;display alr installed msg
  1319.         mov    dx,offset HotKeyMsg
  1320.         mov    ah,9
  1321.         int    21h            ;be kind & disp hot key
  1322.         mov    ax,4c00h + xSecond    ;error level in AL
  1323.         int    21h            ;abot now
  1324.  
  1325. ; ------------    IDIOT IS RUNNING DOS 1, LEAVE THE OLD FASHION WAY!
  1326.  
  1327. Dos1:        mov    dx,offset Dos1Msg
  1328.         mov    ah,9
  1329.         int    21h            ;display msg about DOS 1
  1330.         int    20h            ;no err level for DOS 1
  1331.  
  1332. ; ------------    ENSURE DOS VERSION IS NEWER THAN 2.00
  1333.  
  1334. CheckDos:    or    TsrMode,NewDos        ;assume suing DOS 3.x
  1335.         mov    ah,30h            ;to get DOS version number
  1336.         int    21h            ;version is AL.AH
  1337.         cmp    al,2            ;release 2 or newer?
  1338.         jb    Dos1            ;NO - jump if DOS 1 in use
  1339.         ja    DosFlags        ;jump if DOS 3.x
  1340.         and    TsrMode,not NewDos    ;now, say we use DOS 2.x
  1341.  
  1342. ; ------------    INITIALIZE PTRS TO DOS FLAGS - 1ST InDos
  1343.  
  1344. DosFlags:    mov    ax,3400h        ;to get InDos ptr
  1345.         int    21h            ;ES:BX=seg:off of InDos
  1346.         mov    InDosOff,bx        ;save ptr
  1347.         mov    InDosSeg,es
  1348.  
  1349. ; ------------    WE NEED CritErr TO USE PSP FUNCTIONS IN DOS 2.X (CHIPs WAY)
  1350.  
  1351.         xor    dl,dl            ;DL=0=this is 1st scan
  1352.         mov    CritErrSeg,es        ;DOS seg still in ES
  1353. CritScan:    mov    di,bx            ;start search at InDos
  1354.         mov    cx,2000h        ;search max 1000h words
  1355.         mov    ax,3e80h        ;opcode CMP BYTE PTR [CritErr]
  1356.         cld                ;better serach forward
  1357.  
  1358. CritScan2:    repne    scasw            ;search till found or end
  1359.         jne    NoCritFound        ;jump if CMP not found
  1360.                         ;ES:[DI-2] at:
  1361.                         ;    CMP BYTE PTR [CritErr]
  1362.                         ;    JNZ ...
  1363.                         ;    MOV SP,stack addr
  1364.         cmp    byte ptr es:[di][5],0bch ;really CMP SP there?
  1365.         jne    CritScan2        ;NO - scan again if not
  1366.         mov    ax,word ptr es:[di]    ;now, AX=CritErr offset
  1367.         mov    CritErrOff,ax        ;save it
  1368.         jmp    short InitData        ;OK to end this now
  1369.  
  1370. NoCritFound:    or    dl,dl            ;was this1 st scan?
  1371.         jnz    BadDos            ;NO - CritErr not founbd at all
  1372.         inc    dl            ;DL=1=this is 2nd scan
  1373.         inc    bx            ;try scan at odd/even offset
  1374.         jmp    CritScan        ;scan again
  1375.         
  1376. ; ------------    COULD NOT LOCATE DOS CritErr FLAG - THAT'S AN ERROR
  1377.  
  1378. BadDos:        mov    dx,offset BadDosMsg
  1379.         mov    ah,9
  1380.         int    21h            ;display msg about that
  1381.         mov    ax,4c00h + xBadDos    ;err level in AL
  1382.         int    21h            ;OK to use 4C (DOS >= 2)
  1383.  
  1384. ; ------------    INITIALIZE SYSTEM DATA VARIABLES
  1385.  
  1386. InitData:                    ;store position for stack
  1387.         mov    OurSP,TsrCurtain - ComEntry + 100h + StackSize
  1388.         mov    OurSS,cs        ;stack seg is code seg
  1389.  
  1390.         mov    ax,5100h        ;to get current PSP from DOS
  1391.         int    21h            ;PSP now in BX
  1392.         mov    OurPSP,bx        ;save our PSP
  1393.  
  1394.         mov    ah,2fh            ;to get current DTA from DOS
  1395.         int    21h            ;now, ES:BX=current DTA
  1396.         mov    OurDTAOff,bx        ;save it
  1397.         mov    OurDTASeg,es
  1398.  
  1399.         and    KeyMode,not HotIsShift    ;hotkey is not shift state
  1400.         or    TsrMode,InDosClr    ;will prevent unsafe INT28s
  1401.  
  1402. ; ------------    SAVE VECTORS FOR OUR MONITOR INTERRUPTS
  1403.  
  1404.         mov    ax,3508h        ;BIOS timer0 tick handler
  1405.         int    21h            ;ES:BX=vector
  1406.         mov    OldInt08Off,bx
  1407.         mov    OldInt08Seg,es
  1408.  
  1409.         mov    ax,3509h        ;BIOS kb HW handler
  1410.         int    21h            ;ES:BX=vector
  1411.         mov    OldInt09Off,bx
  1412.         mov    OldInt09Seg,es
  1413.  
  1414.         mov    ax,3513h        ;BIOS disk I/O service
  1415.         int    21h            ;ES:BX=vector
  1416.         mov    OldInt13Off,bx
  1417.         mov    OldInt13Seg,es
  1418.  
  1419.         mov    ax,3516h        ;BIOS kb read
  1420.         int    21h            ;ES:BX=vector
  1421.         mov    OldInt16Off,bx
  1422.         mov    OldInt16Seg,es
  1423.  
  1424.         mov    ax,3521h        ;DOS functions dispatcher
  1425.         int    21h            ;ES:BX=vector
  1426.         mov    OldInt21Off,bx
  1427.         mov    OldInt21Seg,es
  1428.  
  1429.         mov    ax,3528h        ;DOS idle hook
  1430.         int    21h            ;ES:BX=vector
  1431.         mov    OldInt28Off,bx
  1432.         mov    OldInt28Seg,es
  1433.  
  1434. ; ------------    ESTABLISH IRET INT23 TO PREVENT BREAK DURING VECTOR FIX
  1435.  
  1436.         mov    dx,offset NopInt    ;DS:DX=dummy vector to set
  1437.         mov    ax,2523h        ;to set ^C handler through DOS
  1438.         int    21h            ;now, no break will occur
  1439.  
  1440. ; ------------    SAVE VECTORS FOR OUR MONITOR INTERRUPTS
  1441.  
  1442.         mov    ax,2508h        ;to set our INT08h handler
  1443.         mov    dx,offset OurInt08    ;DS:DX=new vector
  1444.         int    21h            ;let DOS set vector
  1445.  
  1446.         mov    ax,2509h        ;to set our INT09h handler
  1447.         mov    dx,offset OurInt09    ;DS:DX=new vector
  1448.         int    21h            ;let DOS set vector
  1449.  
  1450.         mov    ax,2513h        ;to set our INT13h handler
  1451.         mov    dx,offset OurInt13    ;DS:DX=new vector
  1452.         int    21h            ;let DOS set vector
  1453.  
  1454.         mov    ax,2516h        ;to set our INT16h handler
  1455.         mov    dx,offset OurInt16    ;DS:DX=new vector
  1456.         int    21h            ;let DOS set vector
  1457.  
  1458.         mov    ax,2521h        ;to set our INT21h handler
  1459.         mov    dx,offset OurInt21    ;DS:DX=new vector
  1460.         int    21h            ;let DOS set vector
  1461.  
  1462.         mov    ax,2528h        ;to set our INT28h handler
  1463.         mov    dx,offset OurInt28    ;DS:DX=new vector
  1464.         int    21h            ;let DOS set vector
  1465.  
  1466. ; ------------    DISLAY MSG ABOUT HOW WELL THIS IS ALL RUNNING
  1467.  
  1468.         mov    dx,offset FirstMsg
  1469.         mov    ah,9
  1470.         int    21h            ; display confirm msg
  1471.         mov    dx,offset HotKeyMsg
  1472.         mov    ah,9
  1473.         int    21h            ;disp hot key
  1474.  
  1475. ; ------------    EXIT, SAY GOOD BYE TO FRIENDS BEHIND CURTAIN!
  1476.  
  1477.         mov    es,EnvSeg        ;ES=our environment copy
  1478.         mov    ah,49h            ;to let DOS free block
  1479.         int    21h            ;environment copy freed
  1480.  
  1481.         mov    dx,(TsrCurtain-ComEntry+100h+StackSize+15) SHR 4
  1482.         mov    ax,3100h + xOk        ;TSR, AL=err level
  1483.         int    21h
  1484. Init        endp
  1485.  
  1486. ;==============================================================================
  1487.  
  1488. Cseg        ends
  1489.         end    ComEntry
  1490.